package com.xy.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.Scroller;

import com.nineoldandroids.view.ViewHelper;
import com.xy.debug.SystemConfig;


/**
 * @author Ybao
 */
public class SliderLayout extends ViewGroup {
    private int where;
    public final static int LEFT = -1;
    public final static int MID = 0;
    public final static int RIGHT = 1;

    private int mTouchSlop;
    private Scroller mScroller;
    private VelocityTracker mVelocityTracker;
    private static final int VELOCITY = 300;
    private static final int MAX_DURATION = 300;
    public static final int DRAWER = 1;
    public static final int LIKEQQ = 2;
    int lMenuWidth, rMenuWidth;
    float lMenuWidthPS, rMenuWidthPS;
    int defAnim;
    View lMenu, rMenu, mainCev;
    boolean justbroderScroll = false;
    int scrollBroder = 0;
    int[] size;
    float drawerFraction;
    private float downX, downY, tempX;
    private boolean isSliding = false;
    Bitmap shadow;
    Paint paint;

    public SliderLayout(Context context) {
        this(context, null);
    }

    public SliderLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SliderLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }

    private void initView() {
        size = SystemConfig.getScreenSize(getContext());
        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
        mScroller = new Scroller(getContext(), new DecelerateInterpolator());
        drawerFraction = 0.7f;
        lMenuWidthPS = 0.8f;
        rMenuWidthPS = 0.8f;
        setCevView(new View(getContext()));

        shadow = Bitmap.createBitmap(size[0], size[0], Bitmap.Config.ARGB_8888);
        new Canvas(shadow).drawColor(0x66000000);
        paint = new Paint();
        paint.setAlpha(0);
        where = MID;
        scrollBroder = size[0] / 10;
    }

    public void setJustbroderScroll(boolean justbroderScroll) {
        this.justbroderScroll = justbroderScroll;
    }

    public void setScrollBroder(int scrollBroder) {
        this.scrollBroder = scrollBroder;
    }

    public int getDefAnim() {
        return defAnim;
    }

    public void setDefAnim(int defAnim) {
        this.defAnim = defAnim;
    }

    public void setDrawerFraction(float drawerFraction) {
        this.drawerFraction = drawerFraction;
    }

    public void setRightWidthPS(float rightPS) {
        rMenuWidthPS = rightPS;
    }

    public void setLeftWidthPS(float leftPS) {

        lMenuWidthPS = leftPS;
    }

    public int getlMenuWidth() {
        return lMenuWidth;
    }

    public int getrMenuWidth() {
        return rMenuWidth;
    }

    public void setRightView(View rightView) {

        if (rMenu != null) {
            removeView(rMenu);
        }
        rMenu = rightView;
        addView(rMenu);
    }

    public void setLeftView(View leftView) {

        if (lMenu != null) {
            removeView(lMenu);
        }
        lMenu = leftView;
        addView(lMenu);
    }

    public void setCevView(View cevView) {
        if (mainCev != null) {
            removeView(mainCev);
        }
        mainCev = cevView;
        addView(mainCev);
        mainCev.bringToFront();
    }

    public View getMainCev() {
        return mainCev;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        measureChild(mainCev, widthMeasureSpec, heightMeasureSpec);
        int hight = getMeasuredHeight();
        int width = getMeasuredWidth();
        if (lMenu != null && lMenuWidthPS != 0f) {
            LayoutParams mLayoutParams = lMenu.getLayoutParams();
            lMenuWidth = (int) (width * lMenuWidthPS);
            mLayoutParams.width = lMenuWidth;
            mLayoutParams.height = hight;
            measureChild(lMenu, widthMeasureSpec, heightMeasureSpec);
        } else {
            lMenuWidth = 0;
        }

        if (rMenu != null && rMenuWidthPS != 0f) {
            LayoutParams mLayoutParams = rMenu.getLayoutParams();
            rMenuWidth = (int) (width * rMenuWidthPS);
            mLayoutParams.width = rMenuWidth;
            mLayoutParams.height = hight;
            measureChild(rMenu, widthMeasureSpec, heightMeasureSpec);
        } else {
            rMenuWidth = 0;
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (lMenu != null && lMenuWidth != 0) {
            lMenu.layout(-lMenuWidth, 0, 0, getHeight());
        }
        mainCev.layout(0, 0, getWidth(), getHeight());
        if (rMenu != null && rMenuWidth != 0) {
            rMenu.layout(getWidth(), 0, getWidth() + rMenuWidth, getHeight());
        }
    }

    @Override
    public void computeScroll() {
        if (!mScroller.isFinished()) {
            if (mScroller.computeScrollOffset()) {
                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
                postInvalidate();
            }
        }
        super.computeScroll();
    }

    // 监听down事件 但是不拦截 记录按下的点
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (lMenuWidth == 0 && rMenuWidth == 0) {
            return super.dispatchTouchEvent(ev);
        }
        float x = ev.getX();
        float y = ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isSliding = false;
                tempX = downX = x;
                downY = y;
                if (isOnCevView(x, y) && getScrollX() != 0) {
                    return true;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                isSliding = isCanSliding(ev);
                break;
            case MotionEvent.ACTION_UP:
                if (where != MID && isOnCevView(x, y) && !isSliding) {
                    closeMenu();
                    return false;
                }
                break;
            default:
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    public boolean isCanSliding(MotionEvent ev) {
        if (isSliding) {
            return true;
        }
        float moveX;
        float moveY;
        tempX = moveX = ev.getX();
        moveY = ev.getY();
        if (Math.abs(moveX - downX) > mTouchSlop && (Math.abs(moveX - downX) > (Math.abs(moveY - downY)))) {
            int scrollX = getScrollX();
            if (justbroderScroll && scrollX == 0) {
                if (downX < scrollBroder && moveX - downX > 0) {
                    return true;
                } else if (getMeasuredWidth() - downX < scrollBroder && moveX - downX < 0) {
                    return true;
                } else {
                    return false;
                }
            }
            return true;
        }
        return false;
    }


    // 此控件本身是水平滑动控件 所以判断触摸事件是否为水平移动事件，若符合要求则拦截后续完整事件由自己处理
    // 设计原理
    // 判断触摸事件，区分不同类型的事件，水平移动事件由我优先处理，其他事件向下穿
    // （若子控件有相同水平移动事件，则会被屏蔽，解决方法：重写子控件onTouchEvent拦截并处理ACTION_DOWN详细如本空件的onTouchEvent）
    // 两个条件
    // 1、水平移动距离要大于误差值
    // 2、水平移动距离要比垂直移动距离大
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return isSliding;
    }


    // 前提：
    // 1、因为ACTION_DOWN和不符合要求的ACTION_MOVE会默认往下传 子控件不能处理或者该点没有子控件则会回调该事件
    // 为什么：
    // 1、捡漏（反正没子View可以处理，我来处理）
    // 2、必须处理 完整的触摸过程需要 ACTION_DOWN、ACTION_MOVE、ACTION_UP
    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        acquireVelocityTracker(ev);
        float x = ev.getX();
        int scrollX = getScrollX();
        int dateX;
        int endX;
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                if (isSliding) {
                    dateX = (int) (tempX - x);
                    endX = scrollX + dateX;
                    if (endX < -lMenuWidth) {
                        dateX = -lMenuWidth - scrollX;
                    } else if (endX > rMenuWidth) {
                        dateX = rMenuWidth - scrollX;
                    }
                    scrollBy(dateX, 0);
                    tempX = x;
                    //				Log.v(Integer.toString((int) x), "scroll");
                }
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                if (isSliding) {
                    isSliding = false;
                    mVelocityTracker.computeCurrentVelocity(1000);
                    float xVelocity = mVelocityTracker.getXVelocity();
                    if (xVelocity > VELOCITY) {
                        if (scrollX > -lMenuWidth && scrollX < 0) {
                            smoothScrollXTo(scrollX, -lMenuWidth);
                            where = LEFT;
                            break;
                        } else if (scrollX < rMenuWidth && scrollX > 0) {
                            smoothScrollXTo(scrollX, 0);
                            where = MID;
                            break;
                        }
                    } else if (xVelocity < -VELOCITY) {

                        if (scrollX > -lMenuWidth && scrollX < 0) {
                            smoothScrollXTo(scrollX, 0);
                            where = MID;
                            break;
                        } else if (scrollX < rMenuWidth && scrollX > 0) {
                            smoothScrollXTo(scrollX, rMenuWidth);
                            where = RIGHT;

                            break;
                        }
                    }

                    if (scrollX < -lMenuWidth / 2) {
                        smoothScrollXTo(scrollX, -lMenuWidth);
                        where = LEFT;
                    } else if (scrollX > rMenuWidth / 2) {
                        smoothScrollXTo(scrollX, rMenuWidth);
                        where = RIGHT;
                    } else {
                        smoothScrollXTo(scrollX, 0);
                        where = MID;
                    }
                    releaseVelocityTracker();
                }
                break;
            default:
                break;
        }
        return super.onTouchEvent(ev);
    }

    private boolean isOnCevView(float x, float y) {
        int left = -getScrollX();
        int right = left + mainCev.getMeasuredWidth();
        int top = -getScrollY();
        int bottom = top + mainCev.getMeasuredHeight();
        if (left <= x && x <= right && top <= y && y <= bottom) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if (shadow != null && paint != null) {
            RectF mF = new RectF(mainCev.getLeft(), mainCev.getTop(), mainCev.getRight(), mainCev.getBottom());
            canvas.drawBitmap(shadow, null, mF, paint);
        }
    }

    @Override
    public void scrollTo(int x, int y) {
        int oldl = getScrollX();
        super.scrollTo(x, y);
        onScrollChanged(x, 0, oldl, 0);
    }

    @Override
    public void scrollBy(int x, int y) {
        int oldl = getScrollX();
        super.scrollBy(x, y);
        int l = getScrollX();
        onScrollChanged(l, 0, oldl, 0);
    }

    public void smoothScrollXBy(int startX, int dX) {
        // int duration = Math.abs(dX);
        mScroller.startScroll(startX, 0, dX, 0, MAX_DURATION);
        invalidate();
    }

    public void smoothScrollXTo(int startX, int endX) {
        smoothScrollXBy(startX, endX - startX);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        float scale = 0;
        if (l < 0 && lMenuWidth > 0) {
            scale = l * 1.0f / lMenuWidth; // 0 ~ -1
        } else if (l > 0 && rMenuWidth > 0) {
            scale = l * 1.0f / rMenuWidth; // 0 ~ 1
        }
        anim(scale);
    }

    private void anim(float scale) {
        shadowAnim(scale);
        switch (defAnim) {
            case DRAWER:
                drawer(scale);
                break;
            case LIKEQQ:
                likeQQ(scale);
                break;
            default:
                break;
        }

    }

    private void shadowAnim(float scale) {
        if (paint == null) {
            return;
        }
        if (scale < 0) {
            scale = -scale;
        } else if (scale > 0) {

        }
        paint.setAlpha((int) (scale * 255));
    }

    private void drawer(float scale) {
        if (scale < 0) {
            scale = 1 + scale; // 1 ~ 0
            float leftTranslationX = lMenuWidth * scale * drawerFraction;

            // 调用属性动画，设置TranslationX
            ViewHelper.setTranslationX(lMenu, leftTranslationX);
        } else if (scale > 0) {
            scale = 1 - scale; // 1
            // ~
            // 0
            float rightTranslationX = -rMenuWidth * scale * drawerFraction;

            // 调用属性动画，设置TranslationX
            ViewHelper.setTranslationX(rMenu, rightTranslationX);
        }
    }

    private void likeQQ(float scale) {
        if (scale < 0) {
            scale = 1 + scale; // 1 ~ 0
            float mainScale = 0.7f + 0.3f * scale;// 1.0~0.7
            float leftScale = 1.0f - 0.3f * scale;// 0.7~1.0
            float leftAlpha = 1.0f - 0.4f * scale;// 0.6~1.0
            float leftTranslationX = lMenuWidth * scale * 0.8f;

            // 调用属性动画，设置TranslationX
            ViewHelper.setTranslationX(lMenu, leftTranslationX);

            ViewHelper.setScaleX(lMenu, leftScale);
            ViewHelper.setScaleY(lMenu, leftScale);
            ViewHelper.setAlpha(lMenu, leftAlpha);
            // 设置content的缩放的中心点
            ViewHelper.setPivotX(mainCev, 0);
            ViewHelper.setPivotY(mainCev, mainCev.getHeight() / 2);
            ViewHelper.setScaleX(mainCev, mainScale);
            ViewHelper.setScaleY(mainCev, mainScale);

        } else if (scale > 0) {
            scale = 1 - scale; // 1 ~ 0
            float mainScale = 0.7f + 0.3f * scale;// 1.0~0.7
            float rightScale = 1.0f - 0.3f * scale;// 0.7~1.0
            float rightAlpha = 1.0f - 0.4f * scale;// 0.6~1.0
            float rightTranslationX = -rMenuWidth * scale * 0.8f;

            // 调用属性动画，设置TranslationX
            ViewHelper.setTranslationX(rMenu, rightTranslationX);

            ViewHelper.setScaleX(rMenu, rightScale);
            ViewHelper.setScaleY(rMenu, rightScale);
            ViewHelper.setAlpha(rMenu, rightAlpha);
            // 设置content的缩放的中心点
            ViewHelper.setPivotX(mainCev, mainCev.getWidth());
            ViewHelper.setPivotY(mainCev, mainCev.getHeight() / 2);
            ViewHelper.setScaleX(mainCev, mainScale);
            ViewHelper.setScaleY(mainCev, mainScale);
        } else {
            ViewHelper.setScaleX(mainCev, 1);
            ViewHelper.setScaleY(mainCev, 1);
        }
    }

    private void acquireVelocityTracker(final MotionEvent event) {
        if (null == mVelocityTracker) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);
    }

    private void releaseVelocityTracker() {
        if (null != mVelocityTracker) {
            mVelocityTracker.clear();
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

    public void openLMenu() {
        smoothScrollXTo(getScrollX(), -lMenuWidth);
        where = LEFT;

    }

    public void openRMenu() {
        smoothScrollXTo(getScrollX(), rMenuWidth);
        where = RIGHT;
    }

    public void closeMenu() {
        smoothScrollXTo(getScrollX(), 0);
        where = MID;
    }

}
